package com.astar.pathing
{
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.MouseEvent;
	
	public class MyPathFinding extends Sprite
	{
		private var _cellSize:int = 20;
		private var _grid:Grid;
		private var _player:Sprite;
		private var _index:int;
		private var _path:Array;
		private var _moveSpeed:Number = 5;
		
		public function MyPathFinding()
		{
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			
			makePlayer();
			makeGrid();
			stage.addEventListener(MouseEvent.CLICK, onGridClick);
		}
		
		/**
		 * Creates the player sprite. Just a circle here.
		 */
		private function makePlayer():void
		{
			_player = new Sprite();
			_player.graphics.beginFill(0xff0000);
			_player.graphics.drawCircle(0, 0, 5);
			_player.graphics.endFill();
			_player.x = Math.random() * 600;
			_player.y = Math.random() * 600;
			addChild(_player);
		}
		
		/**
		 * Creates a grid with a bunch of random unwalkable nodes.
		 */
		private function makeGrid():void
		{
			_grid = new Grid(30, 30);
			for(var i:int = 0; i < 200; i++)
			{
				_grid.setWalkable(Math.floor(Math.random() * 30),
					Math.floor(Math.random() * 30),
					false);
			}
			drawGrid();
		}
		
		/**
		 * Draws the given grid, coloring each cell according to its state.
		 */
		private function drawGrid():void
		{
			this.graphics.clear();
			for(var i:int = 0; i < _grid.numCols; i++)
			{
				for(var j:int = 0; j < _grid.numRows; j++)
				{
					var node:Node = _grid.getNode(i, j);
					this.graphics.lineStyle(0);
					this.graphics.beginFill(getColor(node));
					this.graphics.drawRect(i * _cellSize, j * _cellSize, _cellSize, _cellSize);
				}
			}
		}
		
		/**
		 * Determines the color of a given node based on its state.
		 */
		private function getColor(node:Node):uint
		{
			if(!node.walkable) return 0;
			if(node == _grid.startNode) return 0xcccccc;
			if(node == _grid.endNode) return 0xcccccc;
			return 0xffffff;
		}
		
		/**
		 * Handles the click event on the GridView. Finds the clicked on cell and toggles its walkable state.
		 */
		private function onGridClick(event:MouseEvent):void
		{			
			
			var startPosX:int = Math.floor(_player.x / _cellSize);
			var startPosY:int = Math.floor(_player.y / _cellSize);
			
			var endPosX:int = Math.floor(mouseX / _cellSize);
			var endPosY:int = Math.floor(mouseY / _cellSize);
			
			var hasBarrier:Boolean = _grid.hasBarrier(startPosX, startPosY, endPosX, endPosY);
			if( hasBarrier )
			{
				_grid.setStartNode(startPosX, startPosY);
				_grid.setEndNode(endPosX, endPosY);
				
				//			drawGrid();
				findPath();
			}
			else
			{
				_path = [_grid.getNode(endPosX, endPosY)];
				_index = 0;
				addEventListener(Event.ENTER_FRAME, onEnterFrame);
			}
			
		}
		
		/**
		 * Creates an instance of AStar and uses it to find a path.
		 */
		private function findPath():void
		{
			var astar:AStar = new AStar();
			if(astar.findPath(_grid) && astar.path.length > 0)
			{
				_path = astar.path;
				_index = 0;
				addEventListener(Event.ENTER_FRAME, onEnterFrame);
			}
		}
		
		/**
		 * Finds the next node on the path and eases to it.
		 */
		private function onEnterFrame(event:Event):void
		{
			var targetX:Number = _path[_index].x * _cellSize + _cellSize / 2;//根据节点列号求得屏幕坐标
			var targetY:Number = _path[_index].y * _cellSize + _cellSize / 2;//根据节点行号求得屏幕坐标
			var dx:Number = targetX - _player.x;
			var dy:Number = targetY - _player.y;
			var dist:Number = Math.sqrt(dx * dx + dy * dy);
			
			//到达当前目的地
			if(dist < _moveSpeed)
			{
				_index++;
				//已到最后一个目的地，则停下
				if( _index >= _path.length )
				{
					_player.x = targetX;
					_player.y = targetY;
					removeEventListener(Event.ENTER_FRAME, onEnterFrame);
					return;
				}
				//未到最后一个目的地，则在index++后重头进行行走逻辑
				else
				{
					onEnterFrame( event );
				}
			}
			//行走
			else
			{
				var angle:Number = Math.atan2( dy, dx );
				var speedX:Number = _moveSpeed * Math.cos( angle );
				var speedY:Number = _moveSpeed * Math.sin( angle );
				_player.x += speedX;
				_player.y += speedY;
			}
		}
	}
}